package com.atguigu.tingshu.payment.service.impl;

import cn.hutool.core.util.IdUtil;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.model.payment.PaymentInfo;
import com.atguigu.tingshu.payment.config.WxPayV3Config;
import com.atguigu.tingshu.payment.mapper.PaymentInfoMapper;
import com.atguigu.tingshu.payment.service.PaymentInfoService;
import com.atguigu.tingshu.payment.service.WxPayService;
import com.atguigu.tingshu.payment.util.PayUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {

	@Autowired
	private PaymentInfoService paymentInfoService;
	@Autowired
	private RSAAutoCertificateConfig rsaAutoCertificateConfig;
	@Autowired
	private WxPayV3Config wxPayV3Config;
	@Autowired
	private RedisTemplate redisTemplate;

	/**
	 * 下单或充值选择微信支付，返回小程序拉起微信支付所需参数
	 *
	 * @param paymentType 支付类型：1301下单  1302充值
	 * @param orderNo     订单/充值订单编号
	 * @return {{"timeStamp":"","package":"","paySign":"","signType":"RSA","nonceStr":""}}}
	 */
	@Override
	public Map<String, String> createJsapi(String paymentType, String orderNo) {
		try {
			//根据订单流水号从paymentInfo表中查找该订单的交易状态
			PaymentInfo paymentInfo = paymentInfoService.savePaymentInfo(paymentType,orderNo);
			//判断支付状态 支付状态：1401-未支付 1402-已支付
			//如果支付状态不是未支付则抛出异常
			if(!SystemConstant.PAYMENT_STATUS_UNPAID.equals(paymentInfo.getPaymentStatus())){
				throw new GuiguException(500, "本地交易记录状态有误" + paymentInfo.getPaymentStatus());
			}

			//对接微信支付,获取小程序端拉取微信支付所需参数
			//创建调用微信支付的JSAPI业务对象
			JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(rsaAutoCertificateConfig).build();

			//创建预下单参数请求对象
			PrepayRequest request = new PrepayRequest();

			Amount amount = new Amount();
			amount.setTotal(paymentInfo.getAmount().multiply(new BigDecimal("100")).intValue());
			request.setAmount(amount);
			request.setAppid(wxPayV3Config.getAppid());
			request.setMchid(wxPayV3Config.getMerchantId());
			request.setDescription(paymentInfo.getContent());
			request.setNotifyUrl(wxPayV3Config.getNotifyUrl());

			//商家订单编号
			request.setOutTradeNo(orderNo);
			//小程序目前还未上线，仅支持应用下的开发者用户进行付款 故这里需要设置开发者用户的openid
			Payer payer = new Payer();
			payer.setOpenid("odo3j4qp-wC3HVq9Z_D9C0cOr0Zs");
			request.setPayer(payer);
			//调用微信获取response包含了掉起支付所需的所有参数,可直接用于前端调起支付
			PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
			if(response != null){
				Map<String,String> map = new HashMap<>();
				map.put("timeStamp",response.getTimeStamp());
				map.put("nonceStr",response.getNonceStr());
				map.put("package",response.getPackageVal());
				map.put("signType",response.getSignType());
				map.put("paySign",response.getPaySign());
				return map;
			}
			return null;
		} catch (GuiguException e) {
			log.error("微信下单失败");
			throw new GuiguException(500, e.getMessage());
		}
	}

	/**
	 * 查询订单支付状态
	 * @param orderNo
	 * @return
	 */
	@Override
	public boolean queryPayStatus(String orderNo) {
		/*//构建JSAPI业务对象
		JsapiServiceExtension service = new JsapiServiceExtension.Builder()
				.config(rsaAutoCertificateConfig).build();
		//构建根据商品订单号查询微信支付订单状态的请求参数
		QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
		request.setMchid(wxPayV3Config.getMerchantId());
		request.setOutTradeNo(orderNo);
		//调用微信支付查询订单状态接口
		Transaction transaction = service.queryOrderByOutTradeNo(request);
		if(transaction != null){
			Transaction.TradeStateEnum tradeState = transaction.getTradeState();
			if(Transaction.TradeStateEnum.SUCCESS == tradeState){
				//交易成功,验证订单金额跟用户实付金额是否一致
				Integer payerTotal = transaction.getAmount().getPayerTotal();
				//根据订单流水号查询到该订单的实际金额
				PaymentInfo paymentInfo = paymentInfoMapper.selectOne(new LambdaQueryWrapper<PaymentInfo>()
						.eq(PaymentInfo::getOrderNo, orderNo));
				if(payerTotal == paymentInfo.getAmount().multiply(new BigDecimal("100")).intValue()){
					return true;
				}
			}
		}
		return false;*/
		//处理核心业务:更新本地交易记录状态
		//1.伪造微信交易对象 封装：订单编号+微信交易号
		Transaction transaction = new Transaction();
		transaction.setOutTradeNo(orderNo);
		transaction.setTransactionId("WX" + IdUtil.getSnowflakeNextId());
		paymentInfoService.updatePaymentInfo(transaction);
		return true;
	}


	/**
	 * 提供给微信支付调用：用户微信付款成功后，微信通知商户支付结果
	 * @param request
	 * @return {code:"SUCCESS",message:"成功"}
	 */
	@Override
	public Map<String, String> wxPayNotify(HttpServletRequest request) {
		//从请求头中获取到支付成功后响应的参数
		//验签的微信支付平台证书序列号/微信支付公钥ID
		String serial = request.getHeader("Wechatpay-Serial");
		//验签的签名值
		String signature = request.getHeader("Wechatpay-Signature");
		//验签的时间戳
		String timestamp = request.getHeader("Wechatpay-Timestamp");
		//验签的随机字符串
		String nonce = request.getHeader("Wechatpay-Nonce");
		//验签的签名值类型
		String signaureType = request.getHeader("Wechatpay-Signature-Type");
		log.info("签名：{}，序列号：{}，随机数：{}，时间戳：{}，签名类型：{}", signature, serial, nonce, timestamp, signaureType);

		//获取请求体中的参数
		String body = PayUtil.readData(request);
		log.info("请求体: {}", body);

		//参数解密
		RequestParam requestParam = new RequestParam.Builder()
				.signature(signature)
				.serialNumber(serial)
				.timestamp(timestamp)
				.nonce(nonce)
				.body(body)
				.build();
		//初始化 NotificationParser解析器对象
		NotificationParser parser = new NotificationParser(rsaAutoCertificateConfig);
		//解密并转换成Transaction交易对象
		Transaction transaction = parser.parse(requestParam, Transaction.class);

		//获取订单流水号
		String outTradeNo = transaction.getOutTradeNo();
		//根据订单流水号查询paymentInfo
		PaymentInfo paymentInfo = paymentInfoService.getOne(
				new LambdaQueryWrapper<PaymentInfo>().eq(PaymentInfo::getOrderNo, outTradeNo));

		//验证支付状态和支付金额
		if(transaction != null){
			if(Transaction.TradeStateEnum.SUCCESS == transaction.getTradeState()
					&& transaction.getAmount().getPayerTotal() == paymentInfo.getAmount().intValue()){
				// 幂等性处理 防止用户重复支付
				String redisKey = RedisConstant.BUSINESS_PREFIX + transaction.getOutTradeNo();
				Boolean isFlag = redisTemplate.opsForValue().setIfAbsent(redisKey, outTradeNo, 25, TimeUnit.HOURS);

				if(isFlag){
					try {
						//更新本地交易记录
						paymentInfoService.updatePaymentInfo(transaction);
						//返回微信应答
						return Map.of("code", "SUCCESS", "message", "成功");
					} catch (Exception e) {
						redisTemplate.delete(redisKey);
						log.error("微信支付回调处理失败");
						throw new GuiguException(500,e.getMessage());
					}
				}

			}
		}
		return null;
	}
}
